package com.arpa.ntocc.common.service.impl;

import cn.hutool.core.util.IdUtil;
import com.arpa.ntocc.common.common.cache.PartyGroupCache;
import com.arpa.ntocc.common.common.cache.PartyGroupCacheDO;
import com.arpa.ntocc.common.common.cache.RoleCache;
import com.arpa.ntocc.common.common.exception.ServiceException;
import com.arpa.ntocc.common.common.util.CommonUtil;
import com.arpa.ntocc.common.common.util.UserUtil;
import com.arpa.ntocc.common.domain.dto.RoleDTO;
import com.arpa.ntocc.common.domain.entity.*;
import com.arpa.ntocc.common.domain.enums.PartyTypeEnum;
import com.arpa.ntocc.common.domain.vo.RoleVO;
import com.arpa.ntocc.common.mapper.PartyRoleMapper;
import com.arpa.ntocc.common.mapper.ResourceMapper;
import com.arpa.ntocc.common.mapper.RoleMapper;
import com.arpa.ntocc.common.service.IRoleConfigService;
import com.arpa.ntocc.common.service.IRoleResourceService;
import com.arpa.ntocc.common.service.IRoleService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户角色 服务实现类
 * </p>
 *
 * @author LEO
 * @since 2019-12-05
 */
@Service
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements IRoleService {

    @javax.annotation.Resource
    RoleCache roleCache;
    @Autowired
    IRoleConfigService roleConfigService;
    @javax.annotation.Resource
    PartyRoleMapper partyRoleMapper;
    @Autowired
    IRoleResourceService roleResourceService;
    @javax.annotation.Resource
    ResourceMapper resourceMapper;

    @javax.annotation.Resource
    PartyGroupCache partyGroupCache;

    /**
     * 保存
     *
     * @param entity
     * @return
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public boolean save(Role entity) {
        if (StringUtils.isBlank(entity.getCode())) {
            entity.setCode(IdUtil.simpleUUID());
        }
        if (StringUtils.isBlank(entity.getCreatedBy())) {
            entity.setCreatedBy(UserUtil.getCode());
        }
        entity.setRole(IdUtil.simpleUUID());
        entity.setType(0);//0非内置
//        entity.setBranchCode(UserUtil.getBranchCode());
        boolean saveFlag = super.save(entity);
        //保存角色配置信息
        List<RoleConfig> roleConfigList = roleConfigService.list(new QueryWrapper<RoleConfig>().lambda().eq(RoleConfig::getRoleCode, "base_role_code"));
        if (!CollectionUtils.isEmpty(roleConfigList)) {
            roleConfigList.forEach(roleConfig -> {
                roleConfig.setId(null);
                roleConfig.setCode(IdUtil.simpleUUID());
                roleConfig.setRoleCode(entity.getCode());
                roleConfig.setCreatedBy(UserUtil.getCode());
            });
            roleConfigService.saveBatch(roleConfigList);
        }
        return saveFlag;
    }

    /**
     * 根据code更新实体
     *
     * @param entity
     * @return
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public int updateByCode(Role entity) {
        if (StringUtils.isBlank(entity.getModifiedBy())) {
            entity.setModifiedBy(UserUtil.getCode());
        }
        entity.setGmtModified(null);
        roleCache.flushCache(entity.getCode());
        return baseMapper.update(entity, new QueryWrapper<Role>().lambda().eq(Role::getCode, entity.getCode()));
    }

    /**
     * 查询列表
     *
     * @param roleDTO
     * @return
     */
    @Override
    public List<RoleVO> queryList(RoleDTO roleDTO) {
        //排序字段名需要驼峰转数据库下划线类型字段名
        if (StringUtils.isNotEmpty(roleDTO.getSortField())) {
            roleDTO.setSortField(CommonUtil.camel2Underline(roleDTO.getSortField()));
        }
        if (UserUtil.getPartyType() != PartyTypeEnum.SUPER_ADMIN) {
            //非SUPER_ADMIN只能查看非内置角色
            roleDTO.setType(0);
        }
        List<RoleVO> roleVOList = baseMapper.queryList(roleDTO);
        if (!roleVOList.isEmpty()) {
            roleVOList.forEach(r -> {
                        PartyGroupCacheDO groupCacheDO = partyGroupCache.get(r.getBranchCode());
                        if (groupCacheDO != null) {
                            r.setBranchName(groupCacheDO.getGroupName());
                        }
                    }
            );
        }


        return roleVOList;
    }

    /**
     * 查询合计,包含总数
     *
     * @param roleDTO
     * @return
     */
    @Override
    public RoleVO queryListSum(RoleDTO roleDTO) {
        RoleVO roleVO = baseMapper.queryListSum(roleDTO);
        return roleVO;
    }

    /**
     * 根据用户code查询角色
     *
     * @param partyCode
     * @return
     */
    @Override
    public List<Role> listByPartyCode(String partyCode) {
        return baseMapper.listByPartyCode(partyCode);
    }

    /**
     * 批量删除用户角色
     *
     * @param codes
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchdel(List<String> codes) {
        //校验是否能删除
        int partyRoleCount = partyRoleMapper.selectCount(new QueryWrapper<PartyRole>().lambda().in(PartyRole::getRoleCode, codes));
        if (partyRoleCount > 0) {
            throw new ServiceException("有用户配置了要删除的角色，请先删除用户角色");
        }
        if (!CollectionUtils.isEmpty(codes)) {
            baseMapper.delete(new QueryWrapper<Role>().lambda().in(Role::getCode, codes));
            //清空缓存
            codes.forEach(code -> {
                roleCache.flushCache(code);
            });
        }
    }

    /**
     * 获取角色资源codelist
     *
     * @param roleDTO
     * @return
     */
    @Override
    public List<String> resourceCodeList(RoleDTO roleDTO) {
        String roleCode = roleDTO.getCode();
        if (StringUtils.isEmpty(roleCode)) {
            throw new ServiceException("角色code不能为空");
        }
        //查询所有父节点
        List<Resource> allParentResourceList = resourceMapper.selectList(new QueryWrapper<Resource>().lambda().select(Resource::getParentCode));
        //存储所有父节点code到list
        List<String> parentCodeList = allParentResourceList.stream()
                .filter(resource -> StringUtils.isNotEmpty(resource.getParentCode()))
                .map(Resource::getParentCode).collect(Collectors.toList());
        List<RoleResource> roleResourceList = roleResourceService.list(new QueryWrapper<RoleResource>().lambda().eq(RoleResource::getRoleCode, roleCode));
        List<String> resourceCodeList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(roleResourceList)) {
            //过滤掉父节点（存在父节点的话前台vue会把所有子节点都选上）
            resourceCodeList = roleResourceList.stream()
                    .filter(roleResource -> !parentCodeList.contains(roleResource.getResourceCode()))
                    .map(RoleResource::getResourceCode).collect(Collectors.toList());
        }
        return resourceCodeList;
    }

    /**
     * 修改角色权限
     *
     * @param entity
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateRoleResource(RoleDTO entity) {
        String roleCode = entity.getCode();
        if (StringUtils.isEmpty(roleCode)) {
            throw new ServiceException("角色code不能为空");
        }
        //删除旧角色资源
        roleResourceService.remove(new QueryWrapper<RoleResource>().lambda().eq(RoleResource::getRoleCode, roleCode));
        //创建新的角色资源
        List<String> recourceCodeList = entity.getResourceCodeList();
        saveRoleResouce(recourceCodeList, roleCode);
    }

    /**
     * 保存角色资源
     *
     * @param recourceCodeList
     */
    private void saveRoleResouce(List<String> recourceCodeList, String roleCode) {
        if (!CollectionUtils.isEmpty(recourceCodeList)) {
            //保存角色权限
            List<RoleResource> roleResourceList = new ArrayList<>();
            recourceCodeList.forEach(resourceCode -> {
                RoleResource roleResource = new RoleResource();
                roleResource.setCode(IdUtil.simpleUUID());
                roleResource.setCreatedBy(UserUtil.getCode());
                roleResource.setRoleCode(roleCode);
                roleResource.setResourceCode(resourceCode);
                roleResourceList.add(roleResource);
            });
            roleResourceService.saveBatch(roleResourceList);
        }
    }
}
